/*
 * ---------------------------------------------------------------------
 * Copyright (c) 2014, 2015 All Right Reserved
 * This software is developed for study and improve coding skill ...
 *
 * Project:  Excellent Coding < EC >
 *
 * ecList.h
 * Eamil:  epengao@126.com
 * Author: Peter Gao
 * Version: First initinal version.
 * --------------------------------------------------------------------
 */

#ifndef EC_LIST_H
#define EC_LIST_H

#include "ecNode.h"

namespace ec {

template<typename T>
class ecList
{
public:
    ecList();
    virtual ~ecList();
    virtual EC_U32 InsertToHead(const T* pData);
    virtual EC_U32 InsertToTail(const T* pData);
    virtual EC_U32 InsertToPos(const T* pData, EC_U32 nIndex);
    virtual EC_U32 DeleteFromHead();
    virtual EC_U32 DeleteFromTail();
    virtual EC_U32 DeleteFromPos(EC_U32 nIndex);
    virtual EC_U32 GetDataFromHead(T* pOutData)               const;
    virtual EC_U32 GetDataFromTail(T* pOutData)               const;
    virtual EC_U32 GetDataFromPos(EC_U32 nIndex, T* pOutData) const;
    virtual EC_U32 GetItemCount() const {return m_nItemCount;}
    virtual void Sort(EC_BOOL bSortType = EC_TRUE);

protected:
    ecNode<T>*      m_pHead;
    ecNode<T>*      m_pTail;
    EC_U32          m_nItemCount;
};

template<typename T>
ecList<T>::ecList()
:m_pHead(EC_NULL)
,m_pTail(EC_NULL)
,m_nItemCount(0)
{
}

template<typename T>
ecList<T>::~ecList()
{
    ecNode<T>* m_pTmp = m_pHead;
    ecNode<T>* m_pTNext = EC_NULL;
    while(EC_NULL != m_pTmp)
    {
        m_pTNext = m_pTmp->m_pNext;
        delete m_pTmp;
        m_pTmp = m_pTNext;
    }
}

template<typename T>
EC_U32 ecList<T>::InsertToHead(const T* pData)
{
    EC_U32 nRet = EC_Err_None;

    ecNode<T>* pNode = new ecNode<T>(pData);
    if(pNode)
    {
        pNode->m_pNext = m_pHead;
        m_pHead = pNode;
        if(EC_NULL == m_pTail)
            m_pTail = pNode;
        m_nItemCount++;
    }
    else
        nRet = EC_Err_Memory_Overflow;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::InsertToTail(const T* pData)
{
    EC_U32 nRet = EC_Err_None;

    ecNode<T>* pNode = new ecNode<T>(pData);
    if(pNode)
    {
        if(EC_NULL != m_pTail)
        {
            m_pTail->m_pNext = pNode;
            m_pTail = pNode;
        }
        else
        {
            m_pTail = pNode;
            m_pHead = pNode;
        }
        m_nItemCount++;
    }
    else
        nRet = EC_Err_Memory_Overflow;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::InsertToPos(const T* pData, EC_U32 nIndex)
{
    EC_U32 nRet = EC_Err_None;
    if((nIndex>=1) && (nIndex < m_nItemCount-1))
    {
        ecNode<T>* pPos = m_pHead;
        for(EC_U32 i = 0; i < nIndex-1; ++i)
            pPos = pPos->m_pNext;
        ecNode<T>* pNode = new ecNode<T>(pData);
        if(EC_NULL != pNode)
        {
            pNode->m_pNext = pPos->m_pNext;
            pPos->m_pNext = pNode;
            m_nItemCount++;
        }
        else
            nRet = EC_Err_Memory_Overflow;
        return nRet;
    }
    else if(nIndex == 0)
        nRet = InsertToHead(pData);
    else if(nIndex == m_nItemCount-1)
        nRet = InsertToTail(pData);
    else
        nRet = EC_Err_BadParam;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::DeleteFromHead()
{
    EC_U32 nRet = EC_Err_None;
    if(EC_NULL != m_pHead)
    {
        ecNode<T>* pNode = m_pHead;
        if(m_pHead == m_pTail)
        {
            m_pHead = EC_NULL;
            m_pTail = EC_NULL;
        }
        else
            m_pHead = m_pHead->m_pNext;

        delete pNode;
        m_nItemCount--;
    }
    else
        nRet = EC_Err_BadParam;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::DeleteFromTail()
{
    EC_U32 nRet = EC_Err_None;
    if(EC_NULL != m_pTail)
    {
        ecNode<T>* pNode = m_pTail;
        if(m_pTail == m_pHead)
        {
            m_pHead = EC_NULL;
            m_pTail = EC_NULL;
            m_nItemCount--;
        }
        else
        {
            m_nItemCount--;
            ecNode<T>* pTmp = m_pHead;
            for(EC_U32 i = 0; i < m_nItemCount-1; ++i)
                pTmp = pTmp->m_pNext;
            m_pTail = pTmp;
        }

        delete pNode;
    }
    else
        nRet = EC_Err_BadParam;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::DeleteFromPos(EC_U32 nIndex)
{
    EC_U32 nRet = EC_Err_None;
    if((nIndex>=1) && (nIndex < m_nItemCount-1))
    {
        ecNode<T>* pPos = m_pHead;
        for(EC_U32 i = 0; i < nIndex-1; ++i)
            pPos = pPos->m_pNext;
        if(EC_NULL != pPos)
        {
            ecNode<T>* pDele = pPos->m_pNext;
            pPos->m_pNext = pDele->m_pNext;
            delete pDele;
            m_nItemCount--;
        }
        else
            nRet = EC_Err_DataNotExist;
        return nRet;
    }
    else if(nIndex == 0)
        nRet = DeleteFromHead();
    else if(nIndex == m_nItemCount-1)
        nRet = DeleteFromTail();
    else
        nRet = EC_Err_BadParam;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::GetDataFromHead(T* pOutData) const
{
    EC_U32 nRet = EC_Err_None;

    if(EC_NULL != m_pHead)
        *pOutData = m_pHead->m_sData;
    else
        nRet = EC_Err_DataNotExist;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::GetDataFromTail(T* pOutData) const
{
    EC_U32 nRet = EC_Err_None;

    if(EC_NULL != m_pTail)
        *pOutData = m_pTail->m_sData;
    else
        nRet = EC_Err_DataNotExist;

    return nRet;
}

template<typename T>
EC_U32 ecList<T>::GetDataFromPos(EC_U32 nIndex, T* pOutData) const
{
    if(nIndex >= m_nItemCount)
        return EC_Err_DataNotExist;

    EC_U32 nRet = EC_Err_None;
    ecNode<T>* pNode = m_pHead;
    for(EC_U32 i = 0; i < nIndex; ++i)
        if(EC_NULL != pNode)
            pNode = pNode->m_pNext;

    if(EC_NULL != pNode)
        *pOutData = pNode->m_sData;
    else
        nRet =  EC_Err_DataNotExist;

    return nRet;
}

template<typename T>
void ecList<T>::Sort(EC_BOOL bSortType /* EC_TRUE*/)
{
    /* TODO */;
}

} /* namespace ec */
#endif /* EC_LIST_H */